package worker

import (
	"context"
	"fmt"
	"gogame/logger"
	"gogame/pb"
	"gogame/server/rpcx"
	"gogame/server/rpcx/procfunc"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/known/anypb"
	"reflect"
	"runtime/debug"
	"strings"
)

type ApiHandle struct{}

type Api2FuncInfo map[string]*FuncInfo

type ApiService struct {
	name             string                 // 模块名
	reflectValue     reflect.Value          // receiver of methods for the service
	reflectType      reflect.Type           // type of the receiver
	reflectMethod    map[string]*methodType // 反射用map
	funcMethod       Api2FuncInfo           // func用map
	api2RegisterType map[string]string      // 接口对应的注册的类型
}

var Api2Service = make(map[string]*ApiService)

// SetRegisterType 设置接口注册的类型
func (a *ApiService) SetRegisterType(api string, registerType string) {
	if a.api2RegisterType == nil {
		a.api2RegisterType = make(map[string]string)
	}
	a.api2RegisterType[api] = registerType
}

// 截取异常所需数据   例: [type.googleapis.com/LoginArgs]:{BindUid:"yace_1657880294_1"}
func fmtErrorArgs(data *anypb.Any) string {
	_str1 := strings.Split(data.String(), "[type.googleapis.com/")[1]
	_strList := strings.Split(_str1, "]:")
	return _strList[0] + _strList[1]
}

// DoApi 接口处理
func (a *ApiHandle) DoApi(ctx context.Context, request *pb.ApiRequest, res *rpcx.Response) (err error) {
	defer func() {
		if r := recover(); r != nil {
			errMsg := fmt.Sprintf(
				"DoApi error!!\nuid:【%s】 api:【%s】 args: %s\nerr--->: 【%s】\n%s\n",
				request.Uid,
				request.Api,
				fmtErrorArgs(request.Data),
				r.(error).Error(),
				debug.Stack(),
			)
			res.S = -888
			res.ErrorMsg = errMsg
			logger.WorkerLog.Error(errMsg)
		}
	}()

	// 分发到对应模块去处理
	_service, _ok := Api2Service[request.ModuleName]
	// 功能模块不存在
	if !_ok {
		res.ErrorMsg = "api not exists!!"
		res.S = -101
		return nil
	}

	_api := request.ApiName
	registerType, ok := _service.api2RegisterType[_api]
	// 接口未注册
	if !ok {
		res.ErrorMsg = "api not exists!!"
		res.S = -103
		return nil
	}

	res.ResponseApi = request.Api

	// 封装为rpcx.Request
	_request := rpcx.NewRequest(ctx, request)

	if registerType == "func" {
		// func接口处理
		err = DoApiFunc(_service, _api, _request, res)
	} else {
		// 反射接口处理
		err = DoApiReflect(_service, _api, _request, res)
	}

	// 未进行接口检测，不予通过
	if res.S == 1 && res.IsCheck != 1 {
		res.S = -777
		res.ErrorMsg = "未进行接口检测，请联系后端处理"
		res.Data = nil
	}

	// request回收
	rpcx.PutRequest(_request)

	return err
}

type ApiInterFace interface {
	GetApi2Func() Api2FuncInfo
}

// Register 模块注册
func Register(name string, rec ApiInterFace) {
	_apiService := &ApiService{}

	_api2Func := rec.GetApi2Func()
	// 优先func
	if _api2Func != nil {
		// func注册
		RegisterFunc(_apiService, name, _api2Func)
	}
	// 反射注册
	RegisterReflect(_apiService, name, rec)

	// 模块注册
	Api2Service[name] = _apiService

	logger.Print("%s init route success", name)

}

// ConvertArgs 接口参数转换
func ConvertArgs(argType reflect.Type, request *pb.ApiRequest) any {
	// 接口参数转换
	_args := reflect.New(argType.Elem()).Interface()
	_ = request.Data.UnmarshalTo(_args.(proto.Message))

	return _args
}

/*
 ------------------------------ 反射处理 ------------------------------
*/

// DoApiReflect 反射接口处理
func DoApiReflect(service *ApiService, api string, request *rpcx.Request, res *rpcx.Response) error {
	_methodType := service.reflectMethod[api]

	// 接口参数转换
	_args := ConvertArgs(_methodType.ArgType, request.ApiRequest)

	// 执行接口逻辑
	_apiArgs := []reflect.Value{
		service.reflectValue,
		reflect.ValueOf(request),
		reflect.ValueOf(_args),
		reflect.ValueOf(res),
	}
	_methodType.method.Func.Call(_apiArgs)

	return nil
}

// RegisterReflect 反射模块注册
func RegisterReflect(apiService *ApiService, name string, handle any) {
	apiService.reflectValue = reflect.ValueOf(handle)
	apiService.reflectType = reflect.TypeOf(handle)

	// 模块注册名不能为空
	if name == "" {
		name = reflect.Indirect(apiService.reflectValue).Type().Name()
		logger.WorkerLog.Warn("Register folder name not is empty!!!")
	}

	// 模块方法注册
	apiService.reflectMethod = DispatchMethods(apiService, name, apiService.reflectType)

}

/*
 ------------------------------ func处理 ------------------------------
*/

type FuncInfo struct {
	F       procfunc.ProcFunc
	Args    proto.Message
	ArgType reflect.Type
}

func FmtFuncInfo(f procfunc.ProcFunc, args proto.Message) *FuncInfo {
	return &FuncInfo{
		F:    f,
		Args: args,
	}
}

// DoApiFunc func接口处理
func DoApiFunc(service *ApiService, api string, request *rpcx.Request, res *rpcx.Response) error {
	_handle := service.funcMethod[api]

	// 接口参数转换
	_args := ConvertArgs(_handle.ArgType, request.ApiRequest)

	// 执行接口逻辑
	_handle.F(request, _args, res)

	return nil
}

// RegisterFunc func模块注册
func RegisterFunc(apiService *ApiService, name string, api2FuncInfo Api2FuncInfo) {
	for api, funcInfo := range api2FuncInfo {
		// 设置接口注册类型
		apiService.SetRegisterType(api, "func")
		// 接口参数类型
		funcInfo.ArgType = reflect.TypeOf(funcInfo.Args)

		//logger.Print("接口【%s.%s】注册成功", name, api)
	}
	apiService.funcMethod = api2FuncInfo
}
